﻿using NHibernate;
using NHibernate.Context;

namespace GdNet.Integrations.NHibernate.SessionManagement
{
    public class NHibernateSessionManager : INHibernateSessionManager
    {
        private static ISessionFactory _sessionFactory = null;

        public NHibernateSessionManager(ISessionFactory sessionFactory)
        {
            _sessionFactory = sessionFactory;
        }

        public ISession GetSession()
        {
            if (CurrentSessionContext.HasBind(_sessionFactory))
            {
                return _sessionFactory.GetCurrentSession();
            }

            var nhSession = _sessionFactory.OpenSession();
            CurrentSessionContext.Bind(nhSession);
            return nhSession;
        }

        public ITransaction BeginTransaction()
        {
            this.RollbackTransaction();
            return this.GetSession().BeginTransaction();
        }

        #region CommitTransaction

        public virtual void CommitTransaction()
        {
            var transaction = this.GetSession().Transaction;
            CommitTransaction(transaction);
        }

        private static void CommitTransaction(ITransaction transaction)
        {
            if (transaction == null || !transaction.IsActive)
            {
                return;
            }

            if (!transaction.WasCommitted)
            {
                transaction.Commit();
            }
        }

        #endregion

        #region RollbackTransaction

        public virtual void RollbackTransaction()
        {
            var transaction = this.GetSession().Transaction;
            RollbackTransaction(transaction);
        }

        private static void RollbackTransaction(ITransaction transaction)
        {
            if (transaction == null || !transaction.IsActive)
            {
                return;
            }

            if (!transaction.WasRolledBack)
            {
                transaction.Rollback();
            }
        }

        #endregion

        #region CloseSession

        public void CloseSession()
        {
            if (!CurrentSessionContext.HasBind(_sessionFactory))
            {
                return;
            }

            using (var session = CurrentSessionContext.Unbind(_sessionFactory))
            {
                RollbackTransaction(session.Transaction);
                CloseSession(session);
            }
        }

        private static void CloseSession(ISession session)
        {
            if (session.IsOpen)
            {
                session.Close();
            }
        }

        #endregion

        #region IDisposable

        public void Dispose()
        {
            CloseSession();
        }

        #endregion
    }
}
